#include "record.h"
#include "gen-record.tab.h"
#include <assert.h>
#include <string.h>

Member::Member() :
	type_(NULL), name_(NULL), next_(NULL) {
}

Record::Record() :
	name_(NULL), members_(NULL), next_(NULL) {
}

void Record::add(Member* member) {
	member->set_next(members_);
	members_ = member;
}

void Record::generate_header(FILE* f) const {
	fprintf(f, "#ifndef RECORD_%s_H__\n", name_);
	fprintf(f, "#define RECORD_%s_H__\n", name_);
	fprintf(f, "\n");

	fprintf(f, "#include \"record/record.h\"\n");
	fprintf(f, "\n");

	fprintf(f, "class Record%s {\n", name_);
	fprintf(f, "public:\n");

	fprintf(f, "    Record%s();\n", name_);
	fprintf(f, "    ~Record%s();\n", name_);
	fprintf(f, "\n");

	fprintf(f, "    void to_binary(std::vector<uint8_t>* buffer);\n");
	fprintf(f, "    bool from_binary(const std::vector<uint8_t>& buffer, int* position);\n");
	fprintf(f, "\n");

	for (const Member* m = members_; m != NULL; m = m->next()) {
		fprintf(f, "    // %s\n", m->name());

		// accessor
		fprintf(f, "    ");
		if (m->type()->reference())
			fprintf(f, "const ");
		fprintf(f, "%s", m->type()->name());
		if (m->type()->reference())
			fprintf(f, "&");
		fprintf(f, " %s() const {\n", m->name());
		fprintf(f, "        return %s_;\n", m->name());
		fprintf(f, "    }\n");

		// mutable accessor
		fprintf(f, "    ");
		fprintf(f, "%s*", m->type()->name());
		fprintf(f, " mutable_%s() const {\n", m->name());
		fprintf(f, "        return &%s_;\n", m->name());
		fprintf(f, "    }\n");

		// mutator
		fprintf(f, "    void set_%s(", m->name());
		if (m->type()->reference())
			fprintf(f, "const ");
		fprintf(f, "%s", m->type()->name());
		if (m->type()->reference())
			fprintf(f, "&");
		
		fprintf(f, " %s) {\n", m->name());
		fprintf(f, "        %s_ = %s;\n", m->name(), m->name());
		fprintf(f, "    }\n");

		fprintf(f, "\n");
	}

	fprintf(f, "private:\n");
	
	// generam membrii
	for (const Member* m = members_; m != NULL; m = m->next()) {
		fprintf(f, "    ");
		fprintf(f, "%s %s_;\n", m->type()->name(), m->name());
	}

	fprintf(f, "};\n");
	fprintf(f, "\n");
	fprintf(f, "#endif\n");
}
